package com.snake.window.snake;

import com.snake.window.MainView;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;

import static java.lang.Thread.sleep;

/**
 * 2 * @Author: Conph
 * 3 * @Date: 2019/7/29 21:33
 * 4
 */
public class Snake implements Runnable {
    private int initialLength = 3;
    private int speed;
    private JPanel gameArea;
    private List<JButton> wallList;
    private JButton jbtnControl;
    private MainView mainView;
    private List<JButton> snakeBlockList;
    private JButton snakeHead;
    private JButton snakeTail;
    private int firstSnakeX;
    private int firstsnakeY;
    private Color snakeColor = new Color(231, 15, 97);
    private volatile int curDirection;
    private volatile boolean goon = false;
    private static int[][] DIRECTION_CONTORL = DIRECTION_CONTORL
            = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    private JButton gameOver;
    private int gameOverWidth = 200;
    private int gameOverHeight = 200;
    private volatile Object controlThreadLock = new Object();
    private Thread controlThread;

    private Food food;
    private int curMoveEnergy = 0;

    public Snake(MainView mainView) throws Exception {
        if(mainView == null) {
            throw new Exception("错误：mainView为null！");
        }
        this.gameArea = mainView.getGameArea();
        this.wallList = mainView.getWallList();
        this.jbtnControl = mainView.getJbtnControl();
        this.mainView = mainView;

        snakeBlockList = new ArrayList<JButton>();

        gameOver = new JButton();

        snakeInitialize();
        addEvent();
    }

    public void snakeInitialize() throws Exception {
        firstSnakeX = mainView.getGameViewWidth() / 2;
        firstsnakeY = mainView.getGameViewHeight() / 2;
        curDirection = 0;

        if(initialLength <= 0) {
            throw new Exception("错误：initialLength为0！");
        }
        //蛇初始长度为1
        if(initialLength == 1) {
            JButton tmp = mainView.drawOneBlock(firstSnakeX, firstsnakeY, snakeColor);
            snakeBlockList.add(tmp);
            snakeHead = snakeTail = tmp;

            return;
        }

        for(int i = 1; i < initialLength; i++) {
            JButton tmp = mainView.drawOneBlock(firstSnakeX, firstsnakeY, snakeColor);
            snakeBlockList.add(tmp);

            if(i == 1) {
                snakeHead = tmp;
            }
            firstSnakeX += mainView.getBlockWith();
        }
        JButton tmp = mainView.drawOneBlock(firstSnakeX, firstsnakeY, snakeColor);
        snakeBlockList.add(tmp);
        snakeTail = tmp;
    }

    public void addEvent() {
        jbtnControl.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseReleased(MouseEvent e) {
            //蛇开始移动
            if (jbtnControl.getText().equals("开始")) {
                food = new Food(Snake.this);
                goon = true;
                synchronized (Snake.this) {
                    controlThread = new Thread(Snake.this);
                    controlThread.start();

                    try {
                        Snake.this.wait();
                    } catch (InterruptedException e1) {
                    }
                }
                jbtnControl.setText("暂停");
            }else if (jbtnControl.getText().equals("暂停")) {
                    goon = false;
                    jbtnControl.setText("继续");
            }else if (jbtnControl.getText().equals("继续")) {
                synchronized (controlThreadLock) {
                    controlThreadLock.notify();
                }
                goon = true;
                jbtnControl.setText("暂停");
                gameArea.requestFocus();
            } else if(jbtnControl.getText().equals("重来")) {
                try {
                    gameOver.setVisible(false);
                    snakeInitialize();
                    gameArea.requestFocus();
                    jbtnControl.setText("暂停");
                    goon = true;
                    synchronized (controlThreadLock) {
                        controlThreadLock.notify();
                    }
                    food.foodRefresh();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
        });

        gameArea.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
            }

            /**
             * 添加按键响应事件，将指定按键进行识别，对当前方向的控制
             * 变量进行改变。
             * @param e
             */
            @Override
            public void keyPressed(KeyEvent e) {
                if(goon == true) {
                    int newDirection = 0;
                    System.out.println(e.getKeyCode());
                    int keyCode = e.getKeyCode();
                    if (keyCode == 37) {
                        newDirection = 0;
                    } else if (keyCode == 39) {
                        newDirection = 1;
                    } else if (keyCode == 40) {
                        newDirection = 3;
                    } else if (keyCode == 38) {
                        newDirection = 2;
                    }
                    int curValue_1 = DIRECTION_CONTORL[curDirection][0];
                    int curValue_2 = DIRECTION_CONTORL[curDirection][1];
                    int newValue_1 = DIRECTION_CONTORL[newDirection][0];
                    int newValue_2 = DIRECTION_CONTORL[newDirection][1];
                    if ((curValue_1 * newValue_1) == 0 && (curValue_2 * newValue_2) == 0) {
                        curDirection = newDirection;
                    }
                    snakeMoveOnce();
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
            }
        });

        //使得单击游戏区域后,重获焦点,响应当前的按钮事件
        gameArea.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                gameArea.requestFocus();
            }
        });
    }
    /*
    将蛇向前移动一次，并判断蛇头的位置是否与障碍重合
     */
    public void snakeMoveOnce() {
        //根据当前方向移动
        int snakeBlockCount = snakeBlockList.size();

            snakeTail.setLocation(snakeHead.getX() +
                            DIRECTION_CONTORL[curDirection][0] * mainView.getBlockWith(),
                    snakeHead.getY() +
                            DIRECTION_CONTORL[curDirection][1] * mainView.getBlockHeight());
            snakeHead = snakeTail;
            for(int i = snakeBlockCount - 1; i > 0; i--) {
                snakeBlockList.set(i, snakeBlockList.get(i - 1));
            }
            snakeBlockList.set(0, snakeHead);
            //此处判断蛇是否吃上食物，是否撞上障碍
            if(snakeHead.getLocation().equals(food.getFoodPoint())) {
                curMoveEnergy += food.getEnergy();
                food.foodRefresh();
            }
            snakeTail = snakeBlockList.get(snakeBlockCount - 1);

            if(!judgeSnakeAlive()) {
                goon = false;
                //处理蛇死亡逻辑，处理相关控件
                System.out.println("dead");
                snakeDead();
            }
    }

    private void snakeGrowOneBlock() {
        snakeHead = mainView.drawOneBlock(snakeHead.getX() +
                        DIRECTION_CONTORL[curDirection][0] * mainView.getBlockWith(),
                snakeHead.getY() +
                        DIRECTION_CONTORL[curDirection][1] * mainView.getBlockHeight(), snakeColor);
        snakeBlockList.add(snakeHead);
        int size = snakeBlockList.size();
        for(;size > 1; size--) {
            snakeBlockList.set(size - 1, snakeBlockList.get(size - 2));
        }
        snakeBlockList.set(0, snakeHead);
    }

    /**
     * 判断蛇的生死
     * @return
     */
    public boolean judgeSnakeAlive() {
        Point headPoint = snakeHead.getLocation();
        boolean result = true;
        //先判断蛇是否撞到墙
        for(int i = 0 ; i < wallList.size() && result; i++) {
            Point wallPoint = wallList.get(i).getLocation();
            if(wallPoint.equals(headPoint)) {
                result = false;

                return false;
            }
        }
        //蛇是否撞到自己的身体
        for(int i =3; i < snakeBlockList.size(); i++) {
            Point snakeBody = snakeBlockList.get(i).getLocation();
            if(snakeBody.equals(headPoint)) {
                return false;
            }
        }

        return result;
    }

    public void snakeDead() {
        //将当前已经死亡的蛇取消显示，并在屏幕上显示死亡信息
        //将按钮处理
        int curLength = snakeBlockList.size();
        for(int i = 0; i < curLength; i++) {
            snakeBlockList.get(i).setVisible(false);
        }

        snakeBlockList.clear();
        gameOver.setBounds((gameArea.getWidth() - gameOverWidth)/2,
                (gameArea.getHeight() - gameOverHeight)/2, gameOverWidth, gameOverHeight);
        gameOver.setText("YOU DEAD！");
        gameArea.add(gameOver);
        gameOver.setVisible(true);
        gameOver.requestFocus();

        jbtnControl.setText("重来");
    }

    public MainView getMainView() {
        return mainView;
    }

    public List<JButton> getSnakeBlockList() {
        return snakeBlockList;
    }

    public JButton getSnakeHead() {
        return snakeHead;
    }

    /**
     * 蛇移动的控制线程
     */
    @Override
    public void run() {
        synchronized (Snake.this) {
            Snake.this.notify();
        }
        gameArea.requestFocus();
        while(true) {
            if (goon) {
                snakeMoveOnce();
                try {
                    Thread.sleep(1000);
                    if(curMoveEnergy > 0) {
                        snakeGrowOneBlock();
                        curMoveEnergy--;
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                synchronized (controlThreadLock) {
                    try {
                        controlThreadLock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }
}
